using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Timing;
using Matrix.Configuration.Events;
using Matrix.Configuration.Services;

namespace Matrix.Application.EventHandlers
{
    /// <summary>
    /// 配置变更本地事件处理器
    /// </summary>
    public class ConfigurationChangedLocalEventHandler :
        ILocalEventHandler<ConfigurationChangedLocalEvent>,
        ITransientDependency
    {
        private readonly ILogger<ConfigurationChangedLocalEventHandler> _logger;
        private readonly IDistributedCache _distributedCache;
        private readonly IClock _clock;
        private readonly IIdempotentEventProcessor _idempotentProcessor;
        private readonly IEventTracer _eventTracer;
        private readonly IConfigurationEventMetrics _metrics;
        private readonly IEventPersistenceService _persistenceService;

        public ConfigurationChangedLocalEventHandler(
            ILogger<ConfigurationChangedLocalEventHandler> logger,
            IDistributedCache distributedCache,
            IClock clock,
            IIdempotentEventProcessor idempotentProcessor,
            IEventTracer eventTracer,
            IConfigurationEventMetrics metrics,
            IEventPersistenceService persistenceService)
        {
            _logger = logger;
            _distributedCache = distributedCache;
            _clock = clock;
            _idempotentProcessor = idempotentProcessor;
            _eventTracer = eventTracer;
            _metrics = metrics;
            _persistenceService = persistenceService;
        }

        public async Task HandleEventAsync(ConfigurationChangedLocalEvent eventData)
        {
            var startTime = _clock.Now;
            var eventId = eventData.EventData.EventId.ToString("N");

            try
            {
                // 开始事件追踪
                var traceContext = await _eventTracer.StartTraceAsync(
                    eventId,
                    nameof(ConfigurationChangedLocalEvent),
                    eventData.Context.TraceId);

                _logger.LogDebug(
                    "开始处理配置变更本地事件: {EventId}, Key: {Key}, Namespace: {Namespace}",
                    eventData.EventData.EventId,
                    eventData.EventData.Key,
                    eventData.EventData.Namespace);

                // 幂等性处理
                var isProcessed = await _idempotentProcessor.ProcessEventAsync(eventId, async () =>
                {
                    // 1. 持久化事件
                    var persistenceStartTime = _clock.Now;
                    await _persistenceService.PersistEventAsync(eventData.EventData);
                    await RecordStepAsync(traceContext, "Persistence", _clock.Now - persistenceStartTime);

                    // 2. 清理本地缓存
                    var cacheStartTime = _clock.Now;
                    await InvalidateLocalCacheAsync(eventData);
                    await RecordStepAsync(traceContext, "CacheInvalidation", _clock.Now - cacheStartTime);

                    // 3. 更新内存配置
                    var memoryStartTime = _clock.Now;
                    await UpdateInMemoryConfigurationAsync(eventData);
                    await RecordStepAsync(traceContext, "MemoryUpdate", _clock.Now - memoryStartTime);

                    // 4. 触发配置监听器
                    var listenerStartTime = _clock.Now;
                    await TriggerConfigurationListenersAsync(eventData);
                    await RecordStepAsync(traceContext, "ListenerTrigger", _clock.Now - listenerStartTime);
                });

                if (!isProcessed)
                {
                    _logger.LogDebug("配置变更本地事件已处理过，跳过: {EventId}", eventId);
                    return;
                }

                var duration = _clock.Now - startTime;

                // 记录成功指标
                _metrics.RecordEventProcessed(
                    nameof(ConfigurationChangedLocalEvent),
                    true,
                    duration,
                    isLocal: true);

                // 完成事件追踪
                await _eventTracer.CompleteTraceAsync(traceContext, true);

                _logger.LogInformation(
                    "配置变更本地事件处理完成: {EventId}, Key: {Key}, Duration: {Duration}ms",
                    eventData.EventData.EventId,
                    eventData.EventData.Key,
                    duration.TotalMilliseconds);
            }
            catch (Exception ex)
            {
                var duration = _clock.Now - startTime;

                // 记录失败指标
                _metrics.RecordEventProcessed(
                    nameof(ConfigurationChangedLocalEvent),
                    false,
                    duration,
                    isLocal: true);

                _logger.LogError(ex,
                    "配置变更本地事件处理失败: {EventId}, Key: {Key}, Error: {Error}",
                    eventData.EventData.EventId,
                    eventData.EventData.Key,
                    ex.Message);

                throw;
            }
        }

        private async Task InvalidateLocalCacheAsync(ConfigurationChangedLocalEvent eventData)
        {
            try
            {
                var cacheKeys = new[]
                {
                    $"config:{eventData.EventData.Namespace}:{eventData.EventData.Key}",
                    $"config:flat:{eventData.EventData.Namespace.Replace('.', ':')}:{eventData.EventData.Key}",
                    $"config:list:{eventData.EventData.Namespace}",
                    $"config:all"
                };

                foreach (var cacheKey in cacheKeys)
                {
                    await _distributedCache.RemoveAsync(cacheKey);
                }

                // 记录缓存命中指标
                foreach (var cacheKey in cacheKeys)
                {
                    _metrics.RecordCacheHit("DistributedCache", false); // 表示缓存失效
                }

                _logger.LogDebug(
                    "本地缓存已清理: {EventId}, CacheKeys: {CacheKeyCount}",
                    eventData.EventData.EventId,
                    cacheKeys.Length);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "清理本地缓存失败: {EventId}", eventData.EventData.EventId);
                // 缓存清理失败不应该影响主流程
            }
        }

        private async Task UpdateInMemoryConfigurationAsync(ConfigurationChangedLocalEvent eventData)
        {
            // 这里可以更新内存中的配置缓存
            // 例如更新静态配置字典、内存缓存等

            try
            {
                // 更新内存配置字典
                var memoryKey = $"{eventData.EventData.Namespace}:{eventData.EventData.Key}";

                // 如果有内存配置存储，在这里更新
                // _memoryConfiguration[memoryKey] = eventData.EventData.NewValue;

                _logger.LogDebug(
                    "内存配置已更新: {EventId}, Key: {MemoryKey}",
                    eventData.EventData.EventId,
                    memoryKey);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "更新内存配置失败: {EventId}", eventData.EventData.EventId);
                // 内存配置更新失败不应该影响主流程
            }
        }

        private async Task TriggerConfigurationListenersAsync(ConfigurationChangedLocalEvent eventData)
        {
            try
            {
                // 触发配置监听器
                // 这里可以调用注册的配置变更回调函数

                _logger.LogDebug(
                    "配置监听器已触发: {EventId}, Key: {Key}",
                    eventData.EventData.EventId,
                    eventData.EventData.Key);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "触发配置监听器失败: {EventId}", eventData.EventData.EventId);
                // 监听器触发失败不应该影响主流程
            }
        }

        private async Task RecordStepAsync(EventTraceContext traceContext, string stepName, TimeSpan duration, bool success = true, string? errorMessage = null)
        {
            try
            {
                await _eventTracer.RecordStepAsync(traceContext, stepName, duration, success, errorMessage);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "记录事件步骤失败: {StepName}", stepName);
            }
        }
    }
}